/**
 * Copyright 2020-2030 Jinhui Technology Co. LTD  All Rights Reserved.
 */
package jgl.vajra.management.netty;

import com.orhanobut.logger.Logger;

import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.WriteBufferWaterMark;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;
import jgl.vajra.management.widget.base.BaseApplication;
import jgl.vajra.management.widget.retrofithelper.utils.AEACCoder;

/**
 * . <br>
 *
 * @author nongkegai<br>
 * @version <br>
 * @date Create in 2021/11/5 16:54 <br>
 * @description 1.0 <br>
 */


public class ImConnection {

    private String host = "106.55.233.164";//正式
//    private String host = "119.91.152.45";//测试
    private Integer port = 35791;
    private Integer low = 32768;
    private Integer high = 65536;
    private EventLoopGroup workerGroup;
    private Bootstrap b;
    private ConnectionListener connectionListener;


    private static class ImConnectionMethods {
        private static final ImConnection INSTANCE = new ImConnection();
    }

    //获取单例
    public static ImConnection getInstance() {
        return ImConnection.ImConnectionMethods.INSTANCE;
    }

    public void connect() {
        doConnect();
    }

    private void doConnect() {

        try {
            if (b == null && workerGroup == null) {
                workerGroup = new NioEventLoopGroup(2);
                b = new Bootstrap();
                b.group(workerGroup);
                b.channel(NioSocketChannel.class);
                b.option(ChannelOption.SO_KEEPALIVE, false);
                b.option(ChannelOption.TCP_NODELAY, true);
                b.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(low, high));
                b.handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        //Netty心跳
                        pipeline.addLast("ping", new IdleStateHandler(0, 50, 0, TimeUnit.SECONDS));
                        //编解码器
                        pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                        pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                        pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
                        pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
                        pipeline.addLast("handler", new ClientHandler());

                    }
                });
            }
            if (!ClientHandler.isLogin) {
                Logger.d("连接中啊");
                ChannelFuture future = b.connect(host, port);
                connectionListener = new ConnectionListener(this, new AEACCoder());
                future.addListener(connectionListener);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void close() {
        Channel channel = BaseApplication.getNettyChannel();
        if (channel == null) {
            return;
        }

        try {
            channel.disconnect();
        } catch (Exception e) {
        }
        try {
            channel.close();
        } catch (Exception e) {
        }
        try {
            //从EventLoop中注销掉channel
            if (channel.pipeline().get("ping") != null) channel.pipeline().remove("ping");
            if (channel.pipeline().get("encoder") != null) channel.pipeline().remove("encoder");
            if (channel.pipeline().get("decoder") != null) channel.pipeline().remove("decoder");
            if (channel.pipeline().get("handler") != null)
                channel.pipeline().remove("handler");
            channel.deregister();
        } catch (Exception e) {
            e.printStackTrace();
        }
        workerGroup.shutdownGracefully();
    }
}
